package com.adinnet.common.utils;

import io.jsonwebtoken.*;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.spec.SecretKeySpec;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class JWTUtil {

    private static final Logger log = LoggerFactory.getLogger(JWTUtil.class);

    private static final String SECURE_KEY = "7y0X%fL!cUBXW5EuJATPrU&$7J2q5Z@RLqEYNMATeQj^d6#oMkzAR573G$xoTa";

    //生成token
    public static String createJWT(String id, String issuer, String subject, long ttlMillis) {
        try {
            SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
            long nowMillis = System.currentTimeMillis();
            Date now = new Date(nowMillis);
            byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(SECURE_KEY);
            Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
            Map<String, Object> claims = new HashMap<String, Object>();//创建payload的私有声明（根据特定的业务需要添加，如果要拿这个做验证，一般是需要和jwt的接收方提前沟通好验证方式的）
            claims.put("userName", subject);
            JwtBuilder builder = Jwts.builder().setId(id)//是JWT的唯一标识，根据业务需要，这个可以设置为一个不重复的值，主要用来作为一次性token,从而回避重放攻击。
                    .setIssuedAt(now);//jwt的签发时间
            if (subject != null) {
                builder.setSubject(subject);
            }
            builder.setClaims(claims);
            if (issuer != null) {
                builder.setIssuer(issuer);//签发者
            }
            builder.signWith(signatureAlgorithm, signingKey);
            long expMillis = nowMillis + ttlMillis;
            Date exp = new Date(expMillis);
            builder.setExpiration(exp);
            return builder.compact();
        } catch (Exception e) {
            log.error("genToken", e);
        }
        return null;
    }


    public static String genCaptchaToken(String id, String code, long ttlMillis) {
        try {
            SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
            long nowMillis = System.currentTimeMillis();
            Date now = new Date(nowMillis);
            byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(SECURE_KEY);
            Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
            Map<String, Object> claims = new HashMap<String, Object>();//创建payload的私有声明（根据特定的业务需要添加，如果要拿这个做验证，一般是需要和jwt的接收方提前沟通好验证方式的）
            claims.put("code", code);
            JwtBuilder builder = Jwts.builder().setId(id).setIssuedAt(now);
            builder.setClaims(claims);
            builder.setIssuer("cosco");
            builder.signWith(signatureAlgorithm, signingKey);
            long expMillis = nowMillis + ttlMillis;
            Date exp = new Date(expMillis);
            builder.setExpiration(exp);
            return builder.compact();
        } catch (Exception e) {
            log.error("genToken", e);
        }
        return null;
    }

    public static String updateToken(String token, long ttlMillis) {
        try {
            Claims claims = validateJWT(token);
            String id = claims.getId();
            String subject = claims.getSubject();
            String issuer = claims.getIssuer();
            return createJWT(id, issuer, subject, ttlMillis);
        } catch (Exception e) {
            log.error("updateToken", e);
        }
        return null;
    }

    public static String updateTokenBase64Code(String token, long ttlMillis) {
        Base64 base64 = new Base64();
        try {
            token = new String(base64.decode(token), "UTF-8");
            Claims claims = validateJWT(token);
            String id = claims.getId();
            String subject = claims.getSubject();
            String issuer = claims.getIssuer();
            String newToken = createJWT(id, issuer, subject, ttlMillis);
            return Base64.encodeBase64String(newToken.getBytes());
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    //验证token
    public static Claims validateJWT(String token) {
        try {
            Claims claims = Jwts.parser()
                    .setSigningKey(DatatypeConverter.parseBase64Binary(SECURE_KEY))
                    .parseClaimsJws(token).getBody();
            return claims;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("token验证失败==》"+e.getMessage());
        }
        return null;
    }

    public static String getCaptcha(String token) throws ServletException {
        try {
            Claims claims = Jwts.parser()
                    .setSigningKey(DatatypeConverter.parseBase64Binary(SECURE_KEY))
                    .parseClaimsJws(token).getBody();
            String code = (String) claims.get("code");
            System.out.println(code);
            return code;
        } catch (final SignatureException e) {
            System.out.println("token is wrong");
            throw new ServletException("Invalid token.");
        }
    }

    public static String getUsrSerUid(HttpServletRequest request) throws ServletException {
        Claims claims = (Claims) request.getAttribute("claims");
        String usrSerUid = (String) claims.get("usrSerUid");
        return usrSerUid;

    }

    public static String getUserName(HttpServletRequest request) throws ServletException {
        Claims claims = (Claims) request.getAttribute("claims");
        String userName = (String) claims.get("userName");
        return userName;

    }

}
